package cn.com.generaldata.os.service.indicator_evaluation.gop_forecast;

import java.math.BigDecimal;

import jsme_matlab.Calculate;

import org.nutz.dao.Chain;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.entity.Record;
import org.nutz.dao.sql.Criteria;
import org.nutz.lang.random.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import cn.com.generaldata.jsme_indicator_system.entity.IndicatorEvaluation;
import cn.com.generaldata.os.pojo.IndicatorEvaluationResult;
import cn.com.generaldata.os.service.indicator_constant.ProvinceIndicatorConstant;
import cn.com.generaldata.os.service.indicator_evaluation.CalculateService;
import cn.com.generaldata.os.service.indicator_evaluation.CalculateServiceHelper;
import cn.com.generaldata.os.util.BeanMapper;
import cn.com.generaldata.os.vo.IndicatorAccountVO;

import com.mathworks.toolbox.javabuilder.MWException;
import com.mathworks.toolbox.javabuilder.MWNumericArray;

/**
 * 三次多项式趋势预测指标计算类.
 */
public class ThreePolynomialCalculateService implements CalculateService {

	private String GOPIndustryName = ProvinceIndicatorConstant.GOP_INDICATOR_NAME;
	private String ForecastYear = ProvinceIndicatorConstant.GOP_FORECAST_YEAR_INDICATOR_NAME;

	private Dao dao;

	private Dao indicatorSystemDao;

	private static final Integer year = 2001;
	private static Logger log = LoggerFactory.getLogger(ThreePolynomialCalculateService.class);
	private CalculateServiceHelper helper;

	@Override
	public void calculateIndicator(IndicatorEvaluation indicator, IndicatorAccountVO indicatorAccountVO) {
		// 预测年份
		Double forecastYear = getForecastYear(indicatorAccountVO) == null ? 3d : getForecastYear(indicatorAccountVO);

		// 输入年份
		Integer nowYear = indicatorAccountVO.getYear();
		double[][] gops = new double[nowYear - year + 1][1];
		int i = year;
		// 获取定基年份到所查年份上一年的
		for (; i <= nowYear; i++) {
			IndicatorAccountVO accountVO = BeanMapper.map(indicatorAccountVO, IndicatorAccountVO.class);
			accountVO.setYear(i);
			Double jsGOP = getProvinceGOP(accountVO);
			if (jsGOP == null) {
				break;
			}
			gops[i - year][0] = jsGOP;
		}

		double[][] gopsNew = new double[i - year][1];
		for (int y = 0, length = i - year; y < length; y++) {
			gopsNew[y][0] = gops[y][0];
		}
		Calculate cal = null;
		try {
			cal = new Calculate();
			Object[] result = cal.huigui(2, gopsNew, forecastYear);

			MWNumericArray r = (MWNumericArray) result[1];
			double[] forecastGOPS = r.getDoubleData();
			if (forecastGOPS != null && forecastGOPS.length != 0) {
				Criteria cri = Cnd.cri();
				cri.where().and("indicator_id", "=", indicator.getId());
				cri.where().and("area_id", "=", indicatorAccountVO.getAreaId());
				Record record = dao.fetch("tbl_indicator_evaluation_res", cri);
				if (record != null) {
					dao.clear("tbl_indicator_evaluation_res", cri);
				}
				int forecastYears = (int) (gopsNew.length + forecastYear);
				for (int j = 0; j < forecastYears; j++) {
					IndicatorAccountVO vo = BeanMapper.map(indicatorAccountVO, IndicatorAccountVO.class);
					vo.setYear(year + j);
					IndicatorEvaluationResult ier = new IndicatorEvaluationResult();
					BeanMapper.copy(vo, ier);
					ier.setIndicatorId(indicator.getId());
					double data = forecastGOPS[j];
					BigDecimal bg = new BigDecimal(data);
					data = bg.setScale(10, BigDecimal.ROUND_HALF_UP).doubleValue();
					ier.setIndicatorValue(data);

					saveIndicatorEvaluationResult(ier);
				}
			}
		} catch (MWException e) {
			log.error("调用Matlab计算三次多项式趋势预测指标错误", e);
		} finally {
			if (cal != null) {
				cal.dispose();
			}
		}
	}

	private void saveIndicatorEvaluationResult(IndicatorEvaluationResult ier) {
		// 保存新记录
		Chain chain = Chain.make("id", R.UU16());
		chain.add("indicator_id", ier.getIndicatorId());
		chain.add("area_id", ier.getAreaId());
		chain.add("year", ier.getYear());
		chain.add("time_type", ier.getTimeType());
		chain.add("year_time", ier.getYearTime());
		chain.add("indicator_value", ier.getIndicatorValue());

		dao.insert("tbl_indicator_evaluation_res", chain);
	}

	/**
	 * 获得省级的海洋生产总值
	 * 
	 * @param indicatorAccountVO
	 * @param indicator
	 * @return
	 */
	private Double getProvinceGOP(IndicatorAccountVO indicatorAccountVO) {
		Double inputOrAccountingIndicatorValue = helper.getInputOrAccountingIndicatorValue(indicatorAccountVO,
				indicatorAccountVO.getYear(), GOPIndustryName);
		return inputOrAccountingIndicatorValue;
	}

	/**
	 * 获得预测年数
	 * 
	 * @param indicatorAccountVO
	 * @param indicator
	 * @return
	 */
	private Double getForecastYear(IndicatorAccountVO indicatorAccountVO) {
		Double inputOrAccountingIndicatorValue = helper.getInputOrAccountingIndicatorValue(indicatorAccountVO,
				indicatorAccountVO.getYear(), ForecastYear);
		return inputOrAccountingIndicatorValue;
	}

	@Override
	public void setDao(Dao dao) {
		this.dao = dao;
	}

	@Override
	public void setIndicatorSystemDao(Dao indicatorSystemDao) {
		this.indicatorSystemDao = indicatorSystemDao;
	}

	@Override
	public void setCalculateServiceHelper(CalculateServiceHelper calculateServiceHelper) {
		helper = calculateServiceHelper;
	}

}
